package reci.journal.utils;

import java.io.*;
import java.net.URI;
import java.util.*;
import java.util.zip.*;

import reci.journal.Const;

/*
 * Copyright (C) 2014 ReciGames
 * See notice in reci.journal.Main.java.
 */

/**zips and unzips*/
public class Zipper
{
	private static final int BUFFER=Const.BUFFER;
	
	/**
	 * @param zipFile
	 * @return if able to unzip
	 */
	public static boolean canUnzip(String zipFile)
	{
		try
		{
			new ZipFile(zipFile);
			return false;
		}
		catch(Exception e)
		{}
		
		return true;
	}
	
	/**
	 * Unzips zipFile to target directory.
	 * 
	 * @param zipFile
	 * @param targetDir
	 * @throws IOException 
	 */
	public static void unzip(String zipFile, String targetDir) throws IOException
	{
		ZipFile zip=null;
		
		try
		{
			zip=new ZipFile(zipFile);
			Enumeration<? extends ZipEntry> zipFileEntries=zip.entries();
			
			// Process each entry
			while(zipFileEntries.hasMoreElements())
			{
				// grab a zip file entry
				ZipEntry entry=(ZipEntry)zipFileEntries.nextElement();
				String currentEntry=entry.getName();
				File destFile=new File(targetDir,currentEntry);
				File destinationParent=destFile.getParentFile();
				
				// create the parent directory structure if needed
				destinationParent.mkdirs();
				
				if(!entry.isDirectory())
				{
					BufferedInputStream is=new BufferedInputStream(zip.getInputStream(entry));
					BufferedOutputStream dest=new BufferedOutputStream(new FileOutputStream(destFile),BUFFER);
					
					int numBytesRead;
					byte[] buffer=new byte[BUFFER];
					
					while((numBytesRead=is.read(buffer,0,BUFFER))>=0)
					{
						dest.write(buffer,0,numBytesRead);
					}
					
					dest.close();
					is.close();
				}
			}
			
			zip.close();
		}
		catch(IOException e)
		{
			throw new IOException("Unable to unzip file.",e);
		}
		finally
		{
			ExtUtil.close(zip);
		}
	}
	
	/**
	 * Zips rootDir directory to zipFile.
	 * 
	 * @param rootDir
	 * @param zipfile
	 * @throws IOException 
	 */
	public static void zip(String rootDir, String zipfile) throws IOException
	{
		ZipOutputStream zout=null;
		
		try
		{
			File directory=new File(rootDir);
			URI base=directory.toURI();
			Deque<File> queue=new LinkedList<>();
			queue.push(directory);
			
			zout=new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(zipfile)));
			
			while(!queue.isEmpty())
			{
				directory=queue.pop();
				
				for(File child : directory.listFiles())
				{
					String name=base.relativize(child.toURI()).getPath();
					
					if(child.isDirectory())
					{
						queue.push(child);
						
						if(name.endsWith("/"))
						{
							name+="/";
						}
						
						zout.putNextEntry(new ZipEntry(name));
					}
					else
					{
						zout.putNextEntry(new ZipEntry(name));
						copy(child,zout);
						zout.closeEntry();
					}
				}
			}
		}
		catch(IOException e)
		{
			throw new IOException("Unable to zip file.",e);
		}
		finally
		{
			ExtUtil.close(zout);
		}
	}
	
	/**
	 * Copies 'file' to 'out', closing only 'file'.
	 * 
	 * @param file
	 * @param out
	 * @throws IOException
	 */
	private static void copy(File file, OutputStream out) throws IOException
	{
		BufferedInputStream in=new BufferedInputStream(new FileInputStream(file));
		ExtUtil.copyDontClose(in,out);
		in.close();
	}
}
